home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ohlfind.zip / PARSER.C < prev    next >
C/C++ Source or Header  |  1990-07-03  |  24KB  |  993 lines

  1. /* The Parsers and associated routines for Find.
  2.    Copyright (C) 1987, 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <pwd.h>
  22. #include <grp.h>
  23. #include <time.h>
  24. #ifndef USG
  25. #include <strings.h>
  26. #else
  27. #include <string.h>
  28. #define index strchr
  29. #define rindex strrchr
  30. #endif
  31. #include "modechange.h"
  32. #include "defs.h"
  33.  
  34. #ifndef S_IFLNK
  35. #define lstat stat
  36. #endif
  37.  
  38. /* no parse_and */
  39. boolean parse_atime ();
  40. boolean parse_close ();
  41. boolean parse_ctime ();
  42. boolean parse_depth ();
  43. boolean parse_exec ();
  44. boolean parse_fstype ();
  45. boolean parse_fulldays ();
  46. boolean parse_group ();
  47. boolean parse_inum ();
  48. boolean parse_links ();
  49. boolean parse_ls ();
  50. boolean parse_mtime ();
  51. boolean parse_name ();
  52. boolean parse_negate ();
  53. boolean parse_newer ();
  54. boolean parse_nogroup ();
  55. boolean parse_nouser ();
  56. boolean parse_ok ();
  57. boolean parse_open ();
  58. boolean parse_or ();
  59. boolean parse_perm ();
  60. boolean parse_permmask ();
  61. boolean parse_print ();
  62. boolean parse_prune ();
  63. boolean parse_regex ();
  64. boolean parse_size ();
  65. boolean parse_type ();
  66. boolean parse_user ();
  67. boolean parse_version ();
  68. boolean parse_xdev ();
  69.  
  70. boolean pred_and ();
  71. boolean pred_atime ();
  72. boolean pred_close ();
  73. boolean pred_ctime ();
  74. /* no pred_depth */
  75. boolean pred_exec ();
  76. boolean pred_fstype ();
  77. /* no pred_fulldays */
  78. boolean pred_group ();
  79. boolean pred_inum ();
  80. boolean pred_links ();
  81. boolean pred_ls ();
  82. boolean pred_mtime ();
  83. boolean pred_name ();
  84. boolean pred_negate ();
  85. boolean pred_newer ();
  86. boolean pred_nogroup ();
  87. boolean pred_nouser ();
  88. boolean pred_ok ();
  89. boolean pred_open ();
  90. boolean pred_or ();
  91. boolean pred_perm ();
  92. boolean pred_permmask ();
  93. boolean pred_print ();
  94. boolean pred_prune ();
  95. boolean pred_regex ();
  96. boolean pred_size ();
  97. boolean pred_type ();
  98. boolean pred_user ();
  99. /* no pred_version */
  100. /* no pred_xdev */
  101.  
  102. long atol ();
  103. struct group *getgrnam ();
  104. struct passwd *getpwnam ();
  105. struct tm *localtime ();
  106. void endgrent ();
  107. void endpwent ();
  108.  
  109. boolean get_num ();
  110. boolean insert_exec_ok ();
  111. boolean insert_num ();
  112. boolean insert_time ();
  113. char *find_pred_name ();
  114. void read_mtab ();
  115.  
  116. #ifdef    DEBUG
  117. char *find_pred_name ();
  118. #endif    /* DEBUG */
  119.  
  120. struct parser_table_t
  121. {
  122.   char *parser_name;
  123.   PFB parser_func;
  124. };
  125.  
  126. struct parser_table_t parse_table[] =
  127. {
  128.   {"!", parse_negate},
  129.   {"(", parse_open},
  130.   {")", parse_close},
  131. #ifdef UNIMPLEMENTED_UNIX
  132.   {"a", parse_and},        /* do-nothing */
  133. #endif
  134.   {"atime", parse_atime},
  135. #ifdef UNIMPLEMENTED_UNIX
  136.   {"cpio", parse_cpio},
  137. #endif
  138.   {"ctime", parse_ctime},
  139.   {"depth", parse_depth},
  140.   {"exec", parse_exec},
  141.   {"fulldays", parse_fulldays},    /* nonstandard */
  142.   {"fstype", parse_fstype},
  143.   {"group", parse_group},
  144.   {"inum", parse_inum},        /* nonstandard, Unix */
  145.   {"links", parse_links},
  146.   {"ls", parse_ls},        /* nonstandard, Unix */
  147.   {"mtime", parse_mtime},
  148.   {"name", parse_name},
  149. #ifdef UNIMPLEMENTED_UNIX
  150.   {"ncpio", parse_ncpio},
  151. #endif
  152.   {"newer", parse_newer},
  153.   {"nogroup", parse_nogroup},
  154.   {"nouser", parse_nouser},
  155.   {"o", parse_or},
  156.   {"or", parse_or},        /* nonstandard */
  157.   {"ok", parse_ok},
  158.   {"perm", parse_perm},
  159.   {"permmask", parse_permmask},    /* nonstandard */
  160.   {"print", parse_print},
  161.   {"prune", parse_prune},
  162.   {"regex", parse_regex},    /* nonstandard */
  163.   {"size", parse_size},
  164.   {"type", parse_type},
  165.   {"user", parse_user},
  166.   {"version", parse_version},
  167.   {"xdev", parse_xdev},
  168.   {0, 0}
  169. };
  170.  
  171. /* Return a pointer to the parser function to invoke for predicate
  172.    SEARCH_NAME.
  173.    Return NULL if SEARCH_NAME is not a valid predicate name. */
  174.  
  175. PFB
  176. find_parser (search_name)
  177.      char *search_name;
  178. {
  179.   int i;
  180.  
  181.   if (*search_name == '-')
  182.     search_name++;
  183.   for (i = 0; parse_table[i].parser_name != 0; i++)
  184.     if (strcmp (parse_table[i].parser_name, search_name) == 0)
  185.       return (parse_table[i].parser_func);
  186.   return (NULL);
  187. }
  188.  
  189. /* The parsers are responsible to continue scanning ARGV for
  190.    their arguments.  Each parser knows what is and isn't
  191.    allowed for itself.
  192.    
  193.    ARGV is the argument array.
  194.    *ARG_PTR is the index to start at in ARGV,
  195.    updated to point beyond the last element consumed.
  196.  
  197.    The predicate structure is updated with the new information. */
  198.  
  199. boolean
  200. parse_atime (argv, arg_ptr)
  201.      char *argv[];
  202.      int *arg_ptr;
  203. {
  204.   return (insert_time (argv, arg_ptr, pred_atime));
  205. }
  206.  
  207. boolean
  208. parse_close (argv, arg_ptr)
  209.      char *argv[];
  210.      int *arg_ptr;
  211. {
  212.   struct pred_struct *our_pred;
  213.  
  214.   our_pred = get_new_pred ();
  215.   our_pred->pred_func = pred_close;
  216. #ifdef    DEBUG
  217.   our_pred->p_name = find_pred_name (pred_close);
  218. #endif    /* DEBUG */
  219.   our_pred->p_type = CLOSE_PAREN;
  220.   our_pred->p_prec = NO_PREC;
  221.   return (true);
  222. }
  223.  
  224. boolean
  225. parse_ctime (argv, arg_ptr)
  226.      char *argv[];
  227.      int *arg_ptr;
  228. {
  229.   return (insert_time (argv, arg_ptr, pred_ctime));
  230. }
  231.  
  232. boolean
  233. parse_depth (argv, arg_ptr)
  234.      char *argv[];
  235.      int *arg_ptr;
  236. {
  237.   do_dir_first = false;
  238.   return (true);
  239. }
  240.  
  241. boolean
  242. parse_exec (argv, arg_ptr)
  243.      char *argv[];
  244.      int *arg_ptr;
  245. {
  246.   return (insert_exec_ok (pred_exec, argv, arg_ptr));
  247. }
  248.  
  249. boolean
  250. parse_fulldays (argv, arg_ptr)
  251.      char *argv[];
  252.      int *arg_ptr;
  253. {
  254.   struct tm *local;
  255.  
  256.   if (full_days == false)
  257.     {
  258.       cur_day_start += DAYSECS;
  259.       local = localtime (&cur_day_start);
  260.       cur_day_start -= local->tm_sec + local->tm_min * 60
  261.     + local->tm_hour * 3600;
  262.       full_days = true;
  263.     }
  264.   return (true);
  265. }
  266.  
  267. boolean
  268. parse_fstype (argv, arg_ptr)
  269.      char *argv[];
  270.      int *arg_ptr;
  271. {
  272.   struct pred_struct *our_pred;
  273.  
  274.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  275.     return (false);
  276.   our_pred = insert_victim (pred_fstype);
  277.   our_pred->args.str = argv[*arg_ptr];
  278.   (*arg_ptr)++;
  279.   read_mtab ();
  280.   return (true);
  281. }
  282.  
  283. boolean
  284. parse_group (argv, arg_ptr)
  285.      char *argv[];
  286.      int *arg_ptr;
  287. {
  288.   struct group *cur_gr;
  289.   struct pred_struct *our_pred;
  290.   int gid, gid_len;
  291.  
  292.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  293.     return (false);
  294.   cur_gr = getgrnam (argv[*arg_ptr]);
  295.   endgrent ();
  296.   if (cur_gr != NULL)
  297.     gid = cur_gr->gr_gid;
  298.   else
  299.     {
  300.       gid_len = strspn (argv[*arg_ptr], "0123456789");
  301.       if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
  302.     return (false);
  303.       gid = atoi (argv[*arg_ptr]);
  304.     }
  305.   our_pred = insert_victim (pred_group);
  306.   our_pred->args.gid = (short) gid;
  307.   (*arg_ptr)++;
  308.   return (true);
  309. }
  310.  
  311. boolean
  312. parse_inum (argv, arg_ptr)
  313.      char *argv[];
  314.      int *arg_ptr;
  315. {
  316.   return (insert_num (argv, arg_ptr, pred_inum));
  317. }
  318.  
  319. boolean
  320. parse_links (argv, arg_ptr)
  321.      char *argv[];
  322.      int *arg_ptr;
  323. {
  324.   return (insert_num (argv, arg_ptr, pred_links));
  325. }
  326.  
  327. boolean
  328. parse_ls (argv, arg_ptr)
  329.      char *argv[];
  330.      int *arg_ptr;
  331. {
  332.   struct pred_struct *our_pred;
  333.  
  334.   our_pred = insert_victim (pred_ls);
  335.   our_pred->side_effects = true;
  336.   return (true);
  337. }
  338.  
  339. boolean
  340. parse_mtime (argv, arg_ptr)
  341.      char *argv[];
  342.      int *arg_ptr;
  343. {
  344.   return (insert_time (argv, arg_ptr, pred_mtime));
  345. }
  346.  
  347. boolean
  348. parse_name (argv, arg_ptr)
  349.      char *argv[];
  350.      int *arg_ptr;
  351. {
  352.   struct pred_struct *our_pred;
  353.  
  354.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  355.     return (false);
  356.   our_pred = insert_victim (pred_name);
  357.   our_pred->args.str = argv[*arg_ptr];
  358.   (*arg_ptr)++;
  359.   return (true);
  360. }
  361.  
  362. boolean
  363. parse_negate (argv, arg_ptr)
  364.      char *argv[];
  365.      int *arg_ptr;
  366. {
  367.   struct pred_struct *our_pred;
  368.  
  369.   our_pred = get_new_pred_chk_op ();
  370.   our_pred->pred_func = pred_negate;
  371. #ifdef    DEBUG
  372.   our_pred->p_name = find_pred_name (pred_negate);
  373. #endif    /* DEBUG */
  374.   our_pred->p_type = UNI_OP;
  375.   our_pred->p_prec = NEGATE_PREC;
  376.   return (true);
  377. }
  378.  
  379. boolean
  380. parse_newer (argv, arg_ptr)
  381.      char *argv[];
  382.      int *arg_ptr;
  383. {
  384.   struct pred_struct *our_pred;
  385.   struct stat stat_newer;
  386.  
  387.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  388.     return (false);
  389.   if (lstat (argv[*arg_ptr], &stat_newer))
  390.     error (1, errno, "%s", argv[*arg_ptr]);
  391.   our_pred = insert_victim (pred_newer);
  392.   our_pred->args.time = stat_newer.st_mtime;
  393.   (*arg_ptr)++;
  394.   return (true);
  395. }
  396.  
  397. boolean
  398. parse_nogroup (argv, arg_ptr)
  399.      char *argv[];
  400.      int *arg_ptr;
  401. {
  402.   struct pred_struct *our_pred;
  403.  
  404.   our_pred = insert_victim (pred_nogroup);
  405.   return (true);
  406. }
  407.  
  408. boolean
  409. parse_nouser (argv, arg_ptr)
  410.      char *argv[];
  411.      int *arg_ptr;
  412. {
  413.   struct pred_struct *our_pred;
  414.  
  415.   our_pred = insert_victim (pred_nouser);
  416.   return (true);
  417. }
  418.  
  419. boolean
  420. parse_ok (argv, arg_ptr)
  421.      char *argv[];
  422.      int *arg_ptr;
  423. {
  424.   boolean insert_exec_ok ();
  425.  
  426.   return (insert_exec_ok (pred_ok, argv, arg_ptr));
  427. }
  428.  
  429. boolean
  430. parse_open (argv, arg_ptr)
  431.      char *argv[];
  432.      int *arg_ptr;
  433. {
  434.   struct pred_struct *our_pred;
  435.  
  436.   our_pred = get_new_pred_chk_op ();
  437.   our_pred->pred_func = pred_open;
  438. #ifdef    DEBUG
  439.   our_pred->p_name = find_pred_name (pred_open);
  440. #endif    /* DEBUG */
  441.   our_pred->p_type = OPEN_PAREN;
  442.   our_pred->p_prec = NO_PREC;
  443.   return (true);
  444. }
  445.  
  446. boolean
  447. parse_or (argv, arg_ptr)
  448.      char *argv[];
  449.      int *arg_ptr;
  450. {
  451.   struct pred_struct *our_pred;
  452.  
  453.   our_pred = get_new_pred ();
  454.   our_pred->pred_func = pred_or;
  455. #ifdef    DEBUG
  456.   our_pred->p_name = find_pred_name (pred_or);
  457. #endif    /* DEBUG */
  458.   our_pred->p_type = BI_OP;
  459.   our_pred->p_prec = OR_PREC;
  460.   return (true);
  461. }
  462.  
  463. boolean
  464. parse_perm (argv, arg_ptr)
  465.      char *argv[];
  466.      int *arg_ptr;
  467. {
  468.   unsigned long perm_val;
  469.   int mode_start = 0;
  470.   struct mode_change *change;
  471.   struct pred_struct *our_pred;
  472.  
  473.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  474.     return (false);
  475.   if (argv[*arg_ptr][0] == '-')
  476.     mode_start = 1;
  477.   
  478.   change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
  479.   if (change == MODE_INVALID)
  480.     error (1, 0, "invalid mode `%s'", argv[*arg_ptr]);
  481.   else if (change == MODE_MEMORY_EXHAUSTED)
  482.     error (1, 0, "virtual memory exhausted");
  483.   perm_val = mode_adjust (0, change);
  484.   mode_free (change);
  485.  
  486.   our_pred = insert_victim (pred_perm);
  487.   if (mode_start)
  488.     /* Set magic flag to compare suid, sgid, sticky bits as well;
  489.        also, true if at least the given bits are set. */
  490.     our_pred->args.perm = (perm_val & 07777) | 010000;
  491.   else
  492.     our_pred->args.perm = perm_val & 0777;
  493.   (*arg_ptr)++;
  494.   return (true);
  495. }
  496.  
  497. boolean
  498. parse_permmask (argv, arg_ptr)
  499.      char *argv[];
  500.      int *arg_ptr;
  501. {
  502.   unsigned long mask_val;
  503.   struct mode_change *change;
  504.   struct pred_struct *our_pred;
  505.  
  506.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  507.     return (false);
  508.  
  509.   change = mode_compile (argv[*arg_ptr], MODE_MASK_PLUS);
  510.   if (change == MODE_INVALID)
  511.     error (1, 0, "invalid mode mask `%s'", argv[*arg_ptr]);
  512.   else if (change == MODE_MEMORY_EXHAUSTED)
  513.     error (1, 0, "virtual memory exhausted");
  514.   mask_val = mode_adjust (0, change);
  515.   mode_free (change);
  516.  
  517.   our_pred = insert_victim (pred_permmask);
  518.   our_pred->args.perm = mask_val;
  519.   (*arg_ptr)++;
  520.   return (true);
  521. }
  522.  
  523. boolean
  524. parse_print (argv, arg_ptr)
  525.      char *argv[];
  526.      int *arg_ptr;
  527. {
  528.   struct pred_struct *our_pred;
  529.  
  530.   our_pred = insert_victim (pred_print);
  531.   /* -print has the side effect of printing.  This prevents us
  532.      from doing undesired multiple printing when the user has
  533.      already specified -print. */
  534.   our_pred->side_effects = true;
  535.   return (true);
  536. }
  537.  
  538. boolean
  539. parse_prune (argv, arg_ptr)
  540.      char *argv[];
  541.      int *arg_ptr;
  542. {
  543.   struct pred_struct *our_pred;
  544.  
  545.   our_pred = insert_victim (pred_prune);
  546.   return (true);
  547. }
  548.  
  549. boolean
  550. parse_regex (argv, arg_ptr)
  551.      char *argv[];
  552.      int *arg_ptr;
  553. {
  554.   struct pred_struct *our_pred;
  555.   struct re_pattern_buffer *re;
  556.   char *error_message;
  557.  
  558.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  559.     return (false);
  560.   our_pred = insert_victim (pred_regex);
  561.   re = (struct re_pattern_buffer *)
  562.     xmalloc (sizeof (struct re_pattern_buffer));
  563.   our_pred->args.regex = re;
  564.   re->allocated = 100;
  565.   re->buffer = xmalloc (re->allocated);
  566.   re->fastmap = NULL;
  567.   re->translate = NULL;
  568.   error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
  569.                       re);
  570.   if (error_message)
  571.     error (1, 0, "%s", error_message);
  572.   (*arg_ptr)++;
  573.   return (true);
  574. }
  575.  
  576. boolean
  577. parse_size (argv, arg_ptr)
  578.      char *argv[];
  579.      int *arg_ptr;
  580. {
  581.   struct pred_struct *our_pred;
  582.   unsigned long num;
  583.   short c_type;
  584.   boolean blk;
  585.   int len;
  586.  
  587.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  588.     return (false);
  589.   len = strlen (argv[*arg_ptr]);
  590.   if (len == 0)
  591.     error (1, 0, "invalid null argument to -size");
  592.   switch (argv[*arg_ptr][len - 1])
  593.     {
  594.     case 'c':
  595.       blk = false;
  596.       argv[*arg_ptr][len - 1] = '\0';
  597.       break;
  598.  
  599.     case '0':
  600.     case '1':
  601.     case '2':
  602.     case '3':
  603.     case '4':
  604.     case '5':
  605.     case '6':
  606.     case '7':
  607.     case '8':
  608.     case '9':
  609.       blk = true;
  610.       break;
  611.  
  612.     default:
  613.       error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]);
  614.     }
  615.   if (!get_num (argv[*arg_ptr], &num, &c_type))
  616.     return (false);
  617.   our_pred = insert_victim (pred_size);
  618.   our_pred->args.size.kind = c_type;
  619.   our_pred->args.size.block = blk;
  620.   our_pred->args.size.size = num;
  621.   (*arg_ptr)++;
  622.   return (true);
  623. }
  624.  
  625. boolean
  626. parse_type (argv, arg_ptr)
  627.      char *argv[];
  628.      int *arg_ptr;
  629. {
  630.   unsigned long type_cell;
  631.   struct pred_struct *our_pred;
  632.  
  633.   if ((argv == NULL) || (argv[*arg_ptr] == NULL)
  634.       || (strlen (argv[*arg_ptr]) != 1))
  635.     return (false);
  636.   switch (argv[*arg_ptr][0])
  637.     {
  638.     case 'b':            /* block special */
  639.       type_cell = S_IFBLK;
  640.       break;
  641.     case 'c':            /* character special */
  642.       type_cell = S_IFCHR;
  643.       break;
  644.     case 'd':            /* directory */
  645.       type_cell = S_IFDIR;
  646.       break;
  647.     case 'f':            /* regular file */
  648.       type_cell = S_IFREG;
  649.       break;
  650. #ifdef S_IFLNK
  651.     case 'l':            /* symbolic link */
  652.       type_cell = S_IFLNK;
  653.       break;
  654. #endif
  655. #ifdef S_IFIFO
  656.     case 'p':            /* pipe */
  657.       type_cell = S_IFIFO;
  658.       break;
  659. #endif
  660. #ifdef S_IFSOCK
  661.     case 's':            /* socket */
  662.       type_cell = S_IFSOCK;
  663.       break;
  664. #endif
  665.     default:            /* none of the above ... nuke em */
  666.       return (false);
  667.     }
  668.   our_pred = insert_victim (pred_type);
  669.   our_pred->args.type = type_cell;
  670.   (*arg_ptr)++;            /* move on to next argument */
  671.   return (true);
  672. }
  673.  
  674. boolean
  675. parse_user (argv, arg_ptr)
  676.      char *argv[];
  677.      int *arg_ptr;
  678. {
  679.   struct passwd *cur_pwd;
  680.   struct pred_struct *our_pred;
  681.   int uid, uid_len;
  682.  
  683.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  684.     return (false);
  685.   cur_pwd = getpwnam (argv[*arg_ptr]);
  686.   endpwent ();
  687.   if (cur_pwd != NULL)
  688.     uid = cur_pwd->pw_uid;
  689.   else
  690.     {
  691.       uid_len = strspn (argv[*arg_ptr], "0123456789");
  692.       if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
  693.     return (false);
  694.       uid = atoi (argv[*arg_ptr]);
  695.     }
  696.   our_pred = insert_victim (pred_user);
  697.   our_pred->args.uid = (short) uid;
  698.   (*arg_ptr)++;
  699.   return (true);
  700. }
  701.  
  702. boolean
  703. parse_version (argv, arg_ptr)
  704.      char *argv[];
  705.      int *arg_ptr;
  706. {
  707.   extern char *version_string;
  708.  
  709.   fprintf (stderr, "%s", version_string);
  710.   return true;
  711. }
  712.  
  713. boolean
  714. parse_xdev (argv, arg_ptr)
  715.      char *argv[];
  716.      int *arg_ptr;
  717. {
  718.   stay_on_filesystem = true;
  719.   return true;
  720. }
  721.  
  722. boolean
  723. insert_exec_ok (func, argv, arg_ptr)
  724.      boolean (*func) ();
  725.      char *argv[];
  726.      int *arg_ptr;
  727. {
  728.   int start, end;        /* Indexes in ARGV of start & end of cmd. */
  729.   int num_paths;        /* Number of "{}" insertions to do. */
  730.   int path_pos;            /* Index in array of "{}" insertions. */
  731.   int vec_pos;            /* Index in array of arg words. */
  732.   struct pred_struct *our_pred;
  733.  
  734.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  735.     return (false);
  736.   start = *arg_ptr;
  737.   for (end = start, num_paths = 0;
  738.        (argv[end] != NULL)
  739.        && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
  740.        end++)
  741.     if (strcmp (argv[end], "{}") == 0)
  742.       num_paths++;
  743.   /* Fail if no command given or no semicolon found. */
  744.   if ((end == start) || (argv[end] == NULL))
  745.     {
  746.       *arg_ptr = end;
  747.       return (false);
  748.     }
  749.   our_pred = insert_victim (func);
  750.   our_pred->side_effects = true;
  751.   our_pred->args.exec_vec.path_loc =
  752.     (short *) xmalloc (sizeof (short) * (num_paths + 1));
  753.   our_pred->args.exec_vec.vec =
  754.     (char **) xmalloc (sizeof (char *) * (end - start + 1));
  755.   for (end = start, path_pos = vec_pos = 0;
  756.        (argv[end] != NULL)
  757.        && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
  758.        end++)
  759.     {
  760.       if (strcmp (argv[end], "{}") == 0)
  761.     our_pred->args.exec_vec.path_loc[path_pos++] = vec_pos;
  762.       our_pred->args.exec_vec.vec[vec_pos++] = argv[end];
  763.     }
  764.   our_pred->args.exec_vec.path_loc[path_pos] = -1;
  765.   our_pred->args.exec_vec.vec[vec_pos] = NULL;
  766.   if (argv[end] == NULL)
  767.     *arg_ptr = end;
  768.   else
  769.     *arg_ptr = end + 1;
  770.   return (true);
  771. }
  772.  
  773. /* Get a number of days and comparison type.
  774.    STR is the ASCII representation.
  775.    Set *NUM_DAYS to the number of days, taken as being from
  776.    the current moment (or possibly midnight).  Thus the sense of the
  777.    comparison type appears to be reversed.
  778.    Set *COMP_TYPE to the kind of comparison that is requested.
  779.  
  780.    Return true if all okay, false if input error.
  781.  
  782.    Used by -atime, -ctime and -mtime (parsers) to
  783.    get the appropriate information for a time predicate processor. */
  784.  
  785. boolean
  786. get_num_days (str, num_days, comp_type)
  787.      char *str;
  788.      unsigned long *num_days;
  789.      enum comparison_type *comp_type;
  790. {
  791.   int len_days;            /* length of field */
  792.  
  793.   if (str == NULL)
  794.     return (false);
  795.   switch (str[0])
  796.     {
  797.     case '+':
  798.       *comp_type = COMP_LT;
  799.       str++;
  800.       break;
  801.     case '-':
  802.       *comp_type = COMP_GT;
  803.       str++;
  804.       break;
  805.     case '0':
  806.     case '1':
  807.     case '2':
  808.     case '3':
  809.     case '4':
  810.     case '5':
  811.     case '6':
  812.     case '7':
  813.     case '8':
  814.     case '9':
  815.       *comp_type = COMP_EQ;
  816.       break;
  817.     default:
  818.       return (false);
  819.     }
  820.  
  821.   /* We know the first char has been reasonable.  Find the
  822.      number of days to play with. */
  823.   len_days = strspn (str, "0123456789");
  824.   if ((len_days == 0) || (str[len_days] != '\0'))
  825.     return (false);
  826.   *num_days = (unsigned long) atol (str);
  827.   return (true);
  828. }
  829.  
  830. /* Insert a time predicate PRED.
  831.    ARGV is a pointer to the argument array.
  832.    ARG_PTR is a pointer to an index into the array, incremented if
  833.    all went well.
  834.  
  835.    Return true if input is valid, false if not.
  836.  
  837.    A new predicate node is assigned, along with an argument node
  838.    obtained with malloc.
  839.  
  840.    Used by -atime, -ctime, and -mtime parsers. */
  841.  
  842. boolean
  843. insert_time (argv, arg_ptr, pred)
  844.      char *argv[];
  845.      int *arg_ptr;
  846.      PFB pred;
  847. {
  848.   struct pred_struct *our_pred;
  849.   unsigned long num_days;
  850.   enum comparison_type c_type;
  851.  
  852.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  853.     return (false);
  854.   if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
  855.     return (false);
  856.   our_pred = insert_victim (pred);
  857.   our_pred->args.info.kind = c_type;
  858.   our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
  859.     + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
  860.   (*arg_ptr)++;
  861. #ifdef    DEBUG
  862.   printf ("inserting %s\n", our_pred->p_name);
  863.   printf ("    type: %s    %s  ",
  864.       (c_type == COMP_GT) ? "gt" :
  865.       ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
  866.       (c_type == COMP_GT) ? " >" :
  867.       ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
  868.   printf ("%ld %s", our_pred->args.info.l_val,
  869.       ctime (&our_pred->args.info.l_val));
  870.   if (c_type == COMP_EQ)
  871.     {
  872.       our_pred->args.info.l_val += DAYSECS;
  873.       printf ("                 <  %ld %s", our_pred->args.info.l_val,
  874.           ctime (&our_pred->args.info.l_val));
  875.       our_pred->args.info.l_val -= DAYSECS;
  876.     }
  877. #endif    /* DEBUG */
  878.   return (true);
  879. }
  880.  
  881. /* Get a number with comparision information.
  882.    The sense of the comparision information is 'normal'; that is,
  883.    '+' looks for inums or links > than the number and '-' less than.
  884.    
  885.    STR is the ASCII representation of the number.
  886.    Set *NUM to the number.
  887.    Set *COMP_TYPE to the kind of comparison that is requested.
  888.  
  889.    Return true if all okay, false if input error.
  890.  
  891.    Used by the -inum and -links predicate parsers. */
  892.  
  893. boolean
  894. get_num (str, num, comp_type)
  895.      char *str;
  896.      unsigned long *num;
  897.      short *comp_type;
  898. {
  899.   int len_num;            /* length of field */
  900.  
  901.   if (str == NULL)
  902.     return (false);
  903.   switch (str[0])
  904.     {
  905.     case '+':
  906.       *comp_type = COMP_GT;
  907.       str++;
  908.       break;
  909.     case '-':
  910.       *comp_type = COMP_LT;
  911.       str++;
  912.       break;
  913.     case '0':
  914.     case '1':
  915.     case '2':
  916.     case '3':
  917.     case '4':
  918.     case '5':
  919.     case '6':
  920.     case '7':
  921.     case '8':
  922.     case '9':
  923.       *comp_type = COMP_EQ;
  924.       break;
  925.     default:
  926.       return (false);
  927.     }
  928.  
  929.   /* We know the first char has been reasonable.  Find the number of
  930.      days to play with. */
  931.   len_num = strspn (str, "0123456789");
  932.   if ((len_num == 0) || (str[len_num] != '\0'))
  933.     return (false);
  934.   *num = (unsigned long) atol (str);
  935.   return (true);
  936. }
  937.  
  938. /* Insert a number predicate.
  939.    ARGV is a pointer to the argument array.
  940.    *ARG_PTR is an index into ARGV, incremented if all went well.
  941.    *PRED is the predicate processor to insert.
  942.  
  943.    Return true if input is valid, false if error.
  944.    
  945.    A new predicate node is assigned, along with an argument node
  946.    obtained with malloc.
  947.  
  948.    Used by -inum and -links parsers. */
  949.  
  950. boolean
  951. insert_num (argv, arg_ptr, pred)
  952.      char *argv[];
  953.      int *arg_ptr;
  954.      PFB pred;
  955. {
  956.   struct pred_struct *our_pred;
  957.   unsigned long num;
  958.   short c_type;
  959.  
  960.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  961.     return (false);
  962.   if (!get_num (argv[*arg_ptr], &num, &c_type))
  963.     return (false);
  964.   our_pred = insert_victim (pred);
  965.   our_pred->args.info.kind = c_type;
  966.   our_pred->args.info.l_val = num;
  967.   (*arg_ptr)++;
  968. #ifdef    DEBUG
  969.   printf ("inserting %s\n", our_pred->p_name);
  970.   printf ("    type: %s    %s  ",
  971.       (c_type == COMP_GT) ? "gt" :
  972.       ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
  973.       (c_type == COMP_GT) ? " >" :
  974.       ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
  975.   printf ("%ld\n", our_pred->args.info.l_val);
  976. #endif    /* DEBUG */
  977.   return (true);
  978. }
  979.  
  980. #ifdef STRSPN_MISSING
  981. int
  982. strspn (str, class)
  983.      char *str, *class;
  984. {
  985.   register char *cl = class;
  986.   register char *st = str;
  987.  
  988.   while (index (class, *st))
  989.     ++st;
  990.   return st - str;
  991. }
  992. #endif
  993.